package com.gitee.sparta.core.cluster;

import com.gitee.sparta.common.IdentityEnum;
import com.gitee.sparta.common.helpers.IsolationHelper;
import com.gitee.sparta.core.bean.cluster.ServerBean;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.nio.channels.SocketChannel;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * 集群信息缓存
 * </p>
 *
 * @author zyred
 * @since v 1.0.0
 */
@Slf4j
public class ClusterCache {

    /**
     * 是否使用 netty 作为数据传输
     */
    private static boolean transportNetty = false;

    /**
     * 系统分配的服务编号
     **/
    @Getter
    private static Integer serverId = null;

    /**
     * leader 的服务编号
     **/
    private static Integer leaderSid = null;

    /**
     * 服务身份，默认是 follower
     **/
    private static IdentityEnum identityEnum = IdentityEnum.FOLLOWER;

    /**
     * leader 节点的隔离
     */
    public static String leaderIsolation = null;

    /**
     * key: server id
     * val: info
     */
    private final static Map<Integer, ServerBean> SERVER_INFO_CACHE = new ConcurrentHashMap<>(32);
    /**
     * key: socket
     * val: server id
     */
    private final static Map<SocketChannel, Integer> NIO_CLIENT_SID = new ConcurrentHashMap<>(32);
    private final static Map<Channel, Integer> NETTY_CLIENT_SID = new ConcurrentHashMap<>(32);
    /**
     * key: isolation
     * val: socket
     */
    private final static Map<String, SocketChannel> ISOLATION_CLI = new ConcurrentHashMap<>(32);
    private final static Map<String, Channel> NETTY_ISOLATION_CLI = new ConcurrentHashMap<>(32);


    public static void putServerInfo(Integer serverId, ServerBean bean) {
        SERVER_INFO_CACHE.put(serverId, bean);
    }


    public static ServerBean getServerInfo(Integer serverId) {
        return SERVER_INFO_CACHE.get(serverId);
    }


    public static IdentityEnum getServerIdentity() {
        return identityEnum;
    }

    public static void setServerIdentity(IdentityEnum identityEnum) {
        ClusterCache.identityEnum = identityEnum;
    }


    public static void putClient(SocketChannel client, Integer sid) {
        NIO_CLIENT_SID.put(client, sid);
        ServerBean bean = SERVER_INFO_CACHE.get(sid);
        if (Objects.nonNull(bean)) {
            ISOLATION_CLI.put(bean.getIsolation(), client);
        }
    }

    public static void putClient (Channel client, Integer sid) {
        NETTY_CLIENT_SID.put(client, sid);
        ServerBean bean = SERVER_INFO_CACHE.get(sid);
        if (Objects.nonNull(bean)) {
            NETTY_ISOLATION_CLI.put(bean.getIsolation(), client);
        }
    }


    public static Integer getSid(SocketChannel client) {
        return NIO_CLIENT_SID.get(client);
    }

    public static Integer getSid(Channel client) {
        return NETTY_CLIENT_SID.get(client);
    }


    public static SocketChannel getClient(String isolation) {
        return ISOLATION_CLI.get(isolation);
    }


    public static Channel getChannel(String isolation) {
        return NETTY_ISOLATION_CLI.get(isolation);
    }

    public static void removeCli(SocketChannel client, Integer sid) {
        NIO_CLIENT_SID.remove(client);
        SERVER_INFO_CACHE.remove(sid);
        ISOLATION_CLI.remove(IsolationHelper.isolation(sid));
    }

    public static void removeCli(Channel client, Integer sid) {
        NETTY_CLIENT_SID.remove(client);
        SERVER_INFO_CACHE.remove(sid);
        NETTY_ISOLATION_CLI.remove(IsolationHelper.isolation(sid));
    }

    public static void setServerId(Integer sid) {
        ClusterCache.serverId = sid;
    }

    public static void setLeaderSid(Integer leaderSid) {
        ClusterCache.leaderSid = leaderSid;
    }

    public static Integer getLeaderSid() {
        return ClusterCache.leaderSid;
    }


    public static boolean isNetty () {
        return ClusterCache.transportNetty;
    }

    public static void setNetty () {
        ClusterCache.transportNetty = true;
    }


    public static Map<Integer, ServerBean> getServerTable () {
        return SERVER_INFO_CACHE;
    }

    public static Set<Channel> getNettyChannels () {
        return NETTY_CLIENT_SID.keySet();
    }

    /**
     * leader 降级为 follower
     */
    public static void demotionFollower () {
        identityEnum = IdentityEnum.FOLLOWER;
        leaderIsolation = null;
        SERVER_INFO_CACHE.clear();
        NIO_CLIENT_SID.clear();
        NETTY_CLIENT_SID.clear();
        ISOLATION_CLI.clear();
        NETTY_ISOLATION_CLI.clear();
    }
}
